var RelativePosition = function(){
    function getLeft( align, rect, rel ){
        var iLeft = 0;
        switch (align.toLowerCase()) {
            case "left" :
                return rect.left - rel.offsetWidth;
            case "clientleft" :
                return rect.left;
            case "center" :
                return ( rect.left + rect.right - rel.offsetWidth ) / 2;
            case "clientright" :
                return rect.right - rel.offsetWidth;
            case "right" :
            default :
                return rect.right;
        };
    };
    function getTop( valign, rect, rel ){
        var iTop = 0;
        switch (valign.toLowerCase()) {
            case "top" :
                return rect.top - rel.offsetHeight;
            case "clienttop" :
                return rect.top;
            case "center" :
                return ( rect.top + rect.bottom - rel.offsetHeight ) / 2;
            case "clientbottom" :
                return rect.bottom - rel.offsetHeight;
            case "bottom" :
            default :
                return rect.bottom;
        };
    };
    //定位元素 相对定位元素
    return function ( fix, rel, options ) {
        //默认值
        var opt = $$.extend({
            align:			"clientleft",//水平方向定位
            vAlign:			"clienttop",//垂直方向定位
            customLeft:		0,//自定义left定位
            customTop:		0,//自定义top定位
            percentLeft:	0,//自定义left百分比定位
            percentTop:		0,//自定义top百分比定位
            adaptive:		false,//是否自适应定位
            reset:			false//自适应定位时是否重新定位
        }, options || {});
        //定义参数
        var rect = $$D.clientRect(fix)
            ,iLeft = getLeft(opt.align, rect, rel) + opt.customLeft
            ,iTop = getTop(opt.vAlign, rect, rel) + opt.customTop;
        //自定义百分比定位
        if (opt.percentLeft) { iLeft += .01 * opt.percentLeft * fix.offsetWidth; };
        if (opt.percentTop) { iTop += .01 * opt.percentTop * fix.offsetHeight; };
        //自适应视窗定位
        if (opt.adaptive) {
            //修正定位参数
            var doc = fix.ownerDocument
                ,maxLeft = doc.clientWidth - rel.offsetWidth
                ,maxTop = doc.clientHeight - rel.offsetHeight;
            if (opt.reset) {
                //自动重新定位
                if (iLeft > maxLeft || iLeft < 0) {
                    iLeft = getLeft(2 * iLeft > maxLeft ? "left" : "right", rect, rel) + opt.customLeft;
                };
                if (iTop > maxTop || iTop < 0) {
                    iTop = getTop(2 * iTop > maxTop ? "top" : "bottom", rect, rel) + opt.customTop;
                };
            } else {
                //修正到适合位置
                iLeft = Math.max(Math.min(iLeft, maxLeft), 0);
                iTop = Math.max(Math.min(iTop, maxTop), 0);
            };
        };
        //加上滚动条
        iLeft += $$D.getScrollLeft(fix); iTop += $$D.getScrollTop(fix);
        //返回定位参数
        return { Left: iLeft, Top: iTop };
    };
}();
//容器集合
var FixedMenu = function(containers, options) {
    this._timerContainer = null;//容器定时器
    this._timerMenu = null;//菜单定时器
    this._frag = document.createDocumentFragment();//碎片对象，保存菜单元素
    this._menus = {};//菜单对象

    this._containers = [];//容器集合

    this._setOptions(options);
    var opt = this.options;

    this._custommenu = opt.menu;

    this.css = opt.css;
    this.hover = opt.hover;
    this.active = opt.active;
    this.tag = opt.tag;
    this.html = opt.html;
    this.relContainer = opt.relContainer;
    this.relative = opt.relative;
    this.attribute = opt.attribute;
    this.property = opt.property;

    this.onBeforeShow = opt.onBeforeShow;

    this.delay = parseInt(opt.delay) || 0;

    //修正自定义容器
    $$A.forEach($$A.isArray(containers) ? containers : [containers], function(o, i){
        //自定义容器 id:定位元素 menu:插入菜单元素
        var pos, menu;
        if ( o.id ) {
            pos = o.id; menu = o.menu ? o.menu : pos;
        } else {
            pos = menu = o;
        };
        pos = $$(pos); menu = $$(menu);
        //容器对象 pos:定位元素 menu:插入菜单元素
        pos && menu && this._iniContainer( i, { "pos": pos, "menu": menu } );
    }, this);

    //初始化程序
    this._iniMenu();
};
FixedMenu.prototype = {
    //设置默认属性
    _setOptions: function(options) {
        this.options = {//默认值
            menu:			[],//自定义菜单集合
            delay:			200,//延迟值(微秒)
            tag:			"div",//默认生成标签
            css:			undefined,//默认样式
            hover:			undefined,//触发菜单样式
            active:			undefined,//显示下级菜单时显示样式
            html:			"",//菜单内容
            relContainer:	false,//是否相对容器定位（否则相对菜单）
            relative:		{ align: "clientleft", vAlign: "bottom" },//定位对象
            attribute:		{},//自定义attribute属性
            property:		{},//自定义property属性
            onBeforeShow:	function(){}//菜单显示时执行
        };
        $$.extend( this.options, options || {} );
    },
    //程序初始化
    _iniMenu: function() {
        this.hide();//隐藏菜单
        this._buildMenu();//生成菜单对象
        this._forEachContainer(this._resetContainer);//重置容器属性
        this._insertMenu(0, 0);//显示菜单
    },
    //根据自定义菜单对象生成程序菜单对象
    _buildMenu: function() {
        //清除旧菜单dom(包括自定义的)
        this._forEachMenu(function(o){
            var elem = o._elem;
            if ( elem ) {
                //防止dom内存泄漏
                $$E.removeEvent( elem, "mouseover", o._event );
                elem.parentNode.removeChild(elem);
                o._elem = o.elem = null;
            };
        });
        //设置菜单默认值
        var options = {
            id:				0,//id
            rank:			0,//排序
            elem:			"",//自定义元素
            tag:			this.tag,
            css:			this.css,
            hover:			this.hover,
            active:			this.active,
            html:			this.html,
            relContainer:	!!this.relContainer,
            relative:		this.relative,
            attribute:		this.attribute,
            property:		this.property
        };
        //先定义"0"顶级菜单
        this._menus = { "0": { "_children": [] } };
        //整理自定义菜单并插入到程序菜单对象
        $$A.forEach(this._custommenu, function(o) {
            //生成菜单对象(由于包含对象，要用深度扩展)
            var menu = $$.deepextend( $$.deepextend( {}, options ), o || {} );
            //去掉相同id菜单，同时排除了id为"0"的菜单
            if ( !!this._menus[ menu.id ] ) { return; };
            //重置属性
            menu._children = []; menu._index = -1;
            this._menus[menu.id] = menu;
        }, this);
        //建立树形结构
        this._forEachMenu(function( o, id, menus ) {
            if ( "0" === id ) { return; };//顶级没有父级菜单
            var parent = this._menus[o.parent];
            //父级菜单不存在或者父级是自己的话，当成一级菜单
            if ( !parent || parent === o ) { parent = menus[o.parent = "0"]; };
            //插入到父级菜单对象的_children中
            parent._children.push(o);
        });
        //整理菜单对象
        this._forEachMenu(function(o) {
            //如果有自定义元素的话先放到碎片文档中
            !!o.elem && ( o.elem = $$(o.elem) ) && this._frag.appendChild(o.elem);
            //修正样式,优先使用自定义元素的class
            if ( !!o.elem && o.elem.className ) {
                o.css = o.elem.className;
            } else if ( o.css === undefined ) { o.css = ""; };
            if ( o.hover === undefined ) { o.hover = o.css; };
            if ( o.active === undefined ) { o.active = o.hover; };
            //对菜单对象的_children集合排序(先按rank再按id排序)
            o._children.sort(function( x, y ) { return x.rank - y.rank || x.id - y.id; });
        });
    },
    //插入菜单
    _insertMenu: function(index, parent) {
        var container = this._containers[index];
        //如果是同一个父级菜单不用重复插入
        if ( container._parent === parent ) { return; };
        container._parent = parent;
        //把原有容器内菜单移到碎片对象中
        $$A.forEach( container._menus, function(o) { o._elem && this._frag.appendChild(o._elem); }, this );
        //重置子菜单对象集合
        container._menus = [];
        //把从父级菜单元素的子菜单对象集合获取的元素插入到容器
        $$A.forEach(this._menus[parent]._children, function( menu, i ){
            this._checkMenu( menu, index );//检查菜单
            container._menus.push(menu);//加入到容器的子菜单集合，方便调用
            container.menu.appendChild(menu._elem);//菜单元素插入到容器
        }, this);
    },
    //检查菜单
    _checkMenu: function(menu, index) {
        //索引保存到菜单对象属性中，方便调用
        menu._index = index;
        //如果菜单对象没有元素
        if ( !menu._elem ) {
            var elem = menu.elem;
            //如果没有自定义元素的话创建一个
            if ( !elem ) { elem = document.createElement(menu.tag); elem.innerHTML = menu.html; };
            //设置property
            $$.extend( elem, menu.property );
            //设置attribute
            var attribute = menu.attribute;
            for (var att in attribute) { elem.setAttribute( att, attribute[att] ); };
            //设置样式
            elem.className = menu.css;
            //设置事件
            menu._event = $$F.bindAsEventListener( this._hoverMenu, this, menu );//用于清除事件
            $$E.addEvent( elem, "mouseover", menu._event );
            //保存到菜单对象
            menu._elem = elem;
        };
    },
    //触发菜单
    _hoverMenu: function(e, menu) {
        var elem = menu._elem;
        //如果是内部元素触发直接返回
        if ( $$D.contains( elem, e.relatedTarget ) || elem === e.relatedTarget ) { return; };
        clearTimeout(this._timerMenu);
        //可能在多个容器间移动，所以全部容器都重新设置样式
        this._forEachContainer(function(o, i){
            if ( o.pos.visibility === "hidden" ) { return; };
            this._resetCss(o);
            //设置当前菜单为active样式
            var menu = o._active;
            if ( menu ) { menu._elem.className = menu.active; };
        });
        //设置当前菜单为触发样式
        if ( this._containers[menu._index]._active !== menu ) { elem.className = menu.hover; };
        //触发显示菜单
        this._timerMenu = setTimeout( $$F.bind( this._showMenu, this, menu ), this.delay );
    },
    //显示菜单
    _showMenu: function(menu) {
        var index = menu._index, container = this._containers[index], child = !!menu._children.length;
        //隐藏不需要的容器
        this._forEachContainer( function(o, i) { i > index && this._hideContainer(o); } );
        //重置当前容器_active
        container._active = null;
        //如果有子级菜单
        if ( child ) {
            //设置当前容器_active
            container._active = menu;
            //显示下一级容器
            index++;//设置索引
            this._checkContainer(index);//检查容器
            this._insertMenu(index, menu.id);//插入菜单
            this._showContainer(menu);//显示容器
        };
        //重置当前容器的css
        this._resetCss(container);
        //设置当前菜单样式
        menu._elem.className = child ? menu.active : menu.hover;
    },
    //初始化容器(索引, 容器元素)
    _iniContainer: function(index, container) {
        var oContainer = container.pos;
        //重置属性
        this._resetContainer(container);
        //添加事件
        $$E.addEvent(oContainer, "mouseover", $$F.bind(function(){ clearTimeout(this._timerContainer); }, this));
        $$E.addEvent(oContainer, "mouseout", $$F.bindAsEventListener(function(e){
            //先判断是否移出到所有容器之外
            var elem = e.relatedTarget,
                isOut = $$A.every(this._containers, function(o){ return  o.pos == elem || !($$D.contains(o.pos, elem)); });
            if ( isOut ) {
                //清除定时器并隐藏
                clearTimeout(this._timerContainer); clearTimeout(this._timerMenu);
                this._timerContainer = setTimeout( $$F.bind( this.hide, this ), this.delay );
            };
        }, this));
        //除了第一个容器外设置浮动样式
        if ( index ) {
            $$D.setStyle(container.pos, {
                position: "absolute", display: "block", margin: 0,
                zIndex: this._containers[index - 1].pos.style.zIndex + 1//要后面的覆盖前面的
            });
        };
        //ie6处理select
        if ( $$B.ie6 ) {
            var iframe = document.createElement("<iframe style='position:absolute;filter:alpha(opacity=0);display:none;'>");
            document.body.insertBefore(iframe, document.body.childNodes[0]);
            container._iframe = iframe;
        };
        //记录索引，方便调用
        container._index = index;
        //插入到容器集合
        this._containers[index] = container;
    },
    //检查容器
    _checkContainer: function(index) {
        if ( index > 0 && !this._containers[index] ) {
            //如果容器不存在，根据前一个容器复制成新容器，第一个容器必须自定义
            var pre = this._containers[index - 1].pos
            //用了新的添加事件方式，没有ie的cloneNode的bug
                ,container = pre.parentNode.insertBefore( pre.cloneNode(false), pre );
            //清除id防止冲突
            container.id = "";
            //初始化容器
            this._iniContainer( index, { "pos": container, "menu": container } );
        };
    },
    //显示容器
    _showContainer: function(menu) {
        var index = menu._index
            ,container = this._containers[index + 1].pos
            ,elem = menu.relContainer ? this._containers[index].pos : menu._elem
            ,pos = RelativePosition( elem, container, menu.relative );
        //执行显示前事件
        this.onBeforeShow(container, menu);
        //定位并显示容器
        $$D.setStyle(container, {
            left: pos.Left + "px", top: pos.Top + "px", visibility: "visible"
        });
        //ie6处理select
        if ( $$B.ie6 ) {
            $$D.setStyle(this._containers[index + 1]._iframe, {
                width: container.offsetWidth + "px",
                height: container.offsetHeight + "px",
                left: pos.Left + "px", top: pos.Top + "px",
                display: ""
            });
        };
    },
    //隐藏容器
    _hideContainer: function(container) {
        //设置隐藏
        $$D.setStyle( container.pos, { left: "-9999px", top: "-9999px", visibility: "hidden" } );
        //重置上一个菜单的触发菜单对象
        this._containers[container._index - 1]._active = null;
        //ie6处理select
        if ( $$B.ie6 ) { container._iframe.style.display = "none"; };
    },
    //重置容器对象属性
    _resetContainer: function(container) {
        container._active = null;//重置触发菜单
        container._menus = [];//重置子菜单对象集合
        container._parent = -1;//重置父级菜单id
    },
    //隐藏菜单
    hide: function() {
        this._forEachContainer(function(o, i){
            if ( i === 0 ) {
                //如果是第一个重设样式和_active
                this._resetCss(o);
            } else {//隐藏容器
                this._hideContainer(o);
            };
        });
    },
    //重设容器菜单样式
    _resetCss: function(container) {
        $$A.forEach( container._menus, function(o, i){ o._elem.className = o.css; }, this );
    },
    //历遍菜单对象集合
    _forEachMenu: function(callback) {
        for ( var id in this._menus ) { callback.call( this, this._menus[id], id, this._menus ); };
    },
    //历遍容器对象集合
    _forEachContainer: function(callback) {
        $$A.forEach( this._containers, callback, this );
    },
    //添加自定义菜单
    add: function(menu) {
        this._custommenu = this._custommenu.concat(menu);
        this._iniMenu();
    },
    //修改自定义菜单
    edit: function(menu) {
        $$A.forEach( $$A.isArray( menu ) ? menu : [ menu ], function(o){
            //如果对应id的菜单存在
            if ( o.id && this._menus[o.id] ) {
                //从自定义菜单中找出对应菜单,并修改
                $$A.every( this._custommenu, function(m, i){
                    if ( m.id === o.id ) {
                        this._custommenu[i] = $$.deepextend( m, o ); return false;
                    };
                    return true;
                    //用every可以跳出循环
                }, this );
            };
        }, this );
        this._iniMenu();
    },
    //删除自定义菜单
    del: function() {
        var ids = Array.prototype.slice.call(arguments);
        this._custommenu = $$A.filter( this._custommenu, function(o){
            return $$A.indexOf(ids, o.id) === -1;
        });
        this._iniMenu();
    }
};

function getID(id){
    return "string" == typeof id ? document.getElementById(id) : id;
}

var Extend = function(destination, source){
    for(var property in source){
        destination[property] = source[property];
    }
    return destination;
}

var CurrentStyle = function(element){
    return element.currentStyle || document.defaultView.getComputedStyle(element, null);
}

var Bind = function(object, fun){
    var args = Array.prototype.slice.call(arguments).slice(2);
    return function(){
        return fun.apply(object, args.concat(Array.prototype.slice.call(arguments)));
    }
}

var forEach = function(array, callback, thisObject){
    if(array.forEach){
        array.forEach(callback, thisObject);
    }else{
        for(var i = 0, len = array.length; i < len; i++){
            callback.call(thisObject, array[i], i, array);
        }
    }
}

var Tween = {
    Quart: {
        easeOut: function(t, b, c, d){
            return -c * ((t = t/d-1)*t*t*t - 1) + b;
        }
    },
    Back: {
        easeOut: function(t, b, c, d, s){
            if (s == undefined) s = 1.70158;
            return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
        }
    },
    Bounce: {
        easeOut: function(t, b, c, d){
            if ((t/=d) < (1/2.75)) {
                return c*(7.5625*t*t) + b;
            } else if (t < (2/2.75)) {
                return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
            } else if (t < (2.5/2.75)) {
                return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
            } else {
                return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
            }
        }
    }
}

//容器对象，滑动对象，切换数量
var SlideTrans = function(container, slider, count, options){
    this._slide = getID(slider);
    this._container = getID(container);
    this._timer = null;
    this._count = Math.abs(count);
    this._target = 0;
    this._t = this._b = this._c = 0;

    this._Index = 0;
    this.SetOptions(options);

    this.Auto = !!this.options.Auto;
    this.Duration = Math.abs(this.options.Duration);
    this.Time = Math.abs(this.options.Time);
    this.Pause = Math.abs(this.options.Pause);
    this.Tween = this.options.Tween;
    this.onStart = this.options.onStart;
    this.onFinish = this.options.onFinish;

    var bVertical = !!this.options.Vertical;
    this._css = bVertical ? "top" : "left";

    var p = CurrentStyle(this._container).position;
    p === "relative" || p === "absolute" || (this._container.style.position = "relative");
    this._container.style.overflow = "hidden";
    this._slide.style.position = "absolute";

    this.Change = this.options.Change ? this.options.Change : this._slide[bVertical ? "offsetHeight" : "offsetWidth"] / this._count;
};

SlideTrans.prototype = {
    SetOptions: function(options){
        this.options = {
            Vertical: true,
            Auto: true,
            Change: 0,
            Duration: 30,
            Time: 10,
            Pause: 3000,
            onStart: function(){},
            onFinish: function(){},
            Tween: Tween.Quart.easeOut
        };
        Extend(this.options, options || {});
    },

    Run: function(index){
        index = undefined && (index = this.Index);
        index < 0 && (index = this._count - 1) || index >= this._count && (index = 0);
        this._target = -Math.abs(this.Change) * (this.Index = index);
        this._t = 0;
        this._b = parseInt(CurrentStyle(this._slide)[this.options.Vertical ? "top" : "left"]);
        this._c = this._target - this._b;

        this.onStart();
        this.Move();
    },

    Move: function(){
        clearTimeout(this._timer);
        if(this._c && this._t < this.Duration){
            this.MoveTo(Math.round(this.Tween(this._t++, this._b, this._c, this.Duration)));
            this._timer = setTimeout(Bind(this, this.Move), this.Time);
        }else{
            this.MoveTo(this._target);
            this.Auto && (this._timer = setTimeout(Bind(this, this.Next), this.Pause));
        }
    },

    MoveTo: function(i){
        this._slide.style[this._css] = i + "px";
    },

    Next: function(){
        this.Run(++this.Index);
    },
    Previous: function(){
        this.Run(--this.Index);
    },

    Stop: function(){
        clearTimeout(this._timer);
        this.MoveTo(this._target);
    }
};

